/*******************************************************************************
 * Copyright (c) 2007, Geophysical Center RAS
 * Sergey Berezin, Dmitry Voitsekhovskiy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms,
 * with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * - Neither the name of the Geophysical Center RAS nor the names
 * of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
using System;
using System.Text;

namespace VisualEsse.THREDDS
{
    public class ThreddsVariableDeclaration
    {
        private string name;
        private int[] min;
        private int[] max;
        private int[] stride;
        private Type type;

        internal ThreddsVariableDeclaration(string name, Type type, int min, int max, int stride)
            :
          this(name, type, new int[1] { min }, new int[1] { max }, new int[1] { stride })
        { }

        internal ThreddsVariableDeclaration(string name, Type type, int min1, int max1, int stride1, int min2, int max2, int stride2)
            :
          this(name, type, new int[2] { min1, min2 }, new int[2] { max1, max2 }, new int[2] { stride1, stride2 })
        { }

        internal ThreddsVariableDeclaration(string name, Type type, int[] min, int[] max, int[] stride)
        {
            this.name = name;
            this.type = type;
            if (min.Length != max.Length || max.Length != stride.Length)
                throw new ArgumentException("Array sizes do not match");
            this.min = min;
            this.max = max;
            this.stride = stride;
        }

        public string Name { get { return name; } }

        public int Dimensions { get { return min.Length; } }

        public bool IsTwoDimensional
        {
            get
            {
                return (Dimensions == 2);
            }
        }
        /// <summary>Returns total array length for this variable</summary>
        public int Length
        {
            get
            {
                int length = 1;
                for (int i = 0; i < min.Length; i++)
                    length *= (int)Math.Ceiling((double)(max[i] - min[i] + 1) / stride[i]);
                return length;
            }
        }

        public int Min { get { return min[0]; } }
        public int Max { get { return max[0]; } }
        public int Stride { get { return stride[0]; } }

        public int GetMin(int index) { return min[index]; }
        public int GetMax(int index) { return max[index]; }
        public int GetStride(int index) { return stride[index]; }

        public Type Type { get { return type; } }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(type.Name);
            sb.Append(' ');
            for (int i = 0; i < Dimensions; i++)
            {
                sb.Append('[');
                sb.Append(min[i]);
                sb.Append(':');
                sb.Append(stride[i]);
                sb.Append(':');
                sb.Append(max[i]);
                sb.Append(']');
            }
            return sb.ToString();
        }

        // TODO: public GetAttributes()        
    }

    public class ThreddsVariable : ThreddsVariableDeclaration
    {
        private Array data = null;

        internal ThreddsVariable(string name, Type type, int[] min, int[] max, int[] stride,Array data) :
          base(name, type, min, max, stride)
            { this.data = data; }

        internal ThreddsVariable(string name, Type type, int min, int max, int stride,Array data) : 
          this(name, type, new int[1] { min }, new int[1] { max }, new int[1] { stride },data)
            { }

        internal ThreddsVariable(string name, Type type, int min1, int max1, int stride1, int min2, int max2, int stride2,Array data) :
          this(name, type, new int[2] { min1, min2 }, new int[2] { max1, max2 }, new int[2] { stride1, stride2 },data)
            { }

        public Array Data
        {
            get
            {
                return data;
            }
            set
            {
                data = value;
            }
        }
    }
}